<?php
/**
* @version $Id: functions_modules.php 336 2007-01-23 08:12:56Z flexiondotorg $
* @copyright (c) 2006 - 2007 Flexion.Org
*            (c) 2004 - 2005 Project Minerva
* @license   http://opensource.org/licenses/gpl-license.php GNU Public License
*/

if (!defined('IN_R3BORN'))
{
	die('Hacking attempt');
}

/**
* Populate: file tree
* @param $path Folder location
* @param $filter Filter to run against file tree
* @param $recurse TRUE or FALSE (defualt = false)
* @param $prefix Set prefix to run against file tree (defualt = '')
*/
function populate_file_tree($path, $filter, $recurse = false, $prefix='')
{
	$out = '';
	$p = substr($path, -1, 1) == '/' ? $path : $path . '/';
	if (@file_exists($p))
	{
		$base = opendir($p);
	}
	if ($base)
	{
		while (($file = readdir($base)) !== false)
		{
			if ($file[0] != '.')
			{
				if (is_dir($p . $file))
				{
					if ($recurse)
					{
						$sub_out = populate_file_tree($p . $file, $filter, $recurse, $prefix . $file . '/');
						$out .= ($sub_out ? ($out ? ', ':'') . $sub_out : '');
					}
					else
					{
						continue;
					}
				}
				elseif (preg_match('~.+\.' . $filter . '$~i', $file))
				{
					$out .= ($out ? ', ':'') . $prefix . $file;
				}
			}
		}
	}
	return $out;
}

/**
* Get: comparison of installed version number of block/module with another version number
* @param $current_version Currently install version of the block/ module or whatever.
* @param $compare_with_version Version to be compared with
* @return $vCompare == 0 if versions are the same, $vCompare < 0 if $compare_with_version is newer than $current_version, $vCompare > 0 if $compare_with_version is older than $current_version
*/
function compare_versions($current_version, $compare_with_version)
{
	$aDB = explode('.', $current_version);
	$aFL = explode('.', $compare_with_version);
	$vCompare = 0;
	for ($i = 0; $i < max(count($aDB), count($aFL)); $i++)
	{
		$vDB = $i < count($aDB) ? intval($aDB[$i]) : 0;
		$vFL = $i < count($aFL) ? intval($aFL[$i]) : 0;
		if ($vDB < $vFL)
		{
			$vCompare = -1;
			break;
		}
		else if ($vDB > $vFL)
		{
			$vCompare = 1;
			break;
		}
	}

	return $vCompare;
}

/**
* Get: module version
* @param $modulename Name of module
*/
function getModuleVersion($modulename)
{
	global $mvModules;
	return $mvModules[$modulename]['version'];
}

/**
* Get: installed modules
* @param $status 
*/
function getInstalledModules($status)
{
	global $db;
	$sql = 'SELECT * FROM ' . MODULES_TABLE;
	if (!($result = $db->sql_query($sql)))
	{
		message_die(CRITICAL_ERROR, 'Could not query module information', '', __LINE__, __FILE__, $sql);
	}
	while ($row = $db->sql_fetchrow($result))
	{

		$modulename = $row['module_name'];

		if (getModuleStatus($modulename) == $status)
		{
			$installed[] = $modulename;
		}
	}
	return $installed;
}

function buildModuleFilePath($modulename, $filename)
{
	global $root_path;
	return $root_path . 'modules/' . $modulename . '/' . $filename;
}


// Create a valid URL to a module from outside the context of the running module
// Useful in hooks and module page headers (mvHeaders.php) where append_sid can't determine the appropriate running module dynamically.
/**
* 
* @param 
*/
function buildModuleURL($modulename, $filename = '', $params = '', $redirect = false)
{
	global $phpEx;

	$url = ($redirect) ? 'index.' . $phpEx . '&amp;module=' . $modulename : 'index.' . $phpEx . '?module=' . $modulename;

	if ($filename != '')
	{
		$url.= '&amp;file=' . $filename;
	}

	$url .= $params;

	return $url;
}

function module_url($url, $force_module = '', $redirect = false)
{
	global $root_path, $mvModules, $mvModuleName, $phpEx;

	$mvModuleSearch = ($force_module != '') ? $force_module : $mvModuleName;
	$first_sep = ($redirect) ? '&amp;' : '?';

	$matches = array();
	if (preg_match("~((admin)?[^\/\?&]*)\.$phpEx(?:[\?&]([^<>\s]*))?$~i", $url, $matches))
	{
		// $matches[1] = "admin_file"
		// $matches[2] = "admin"
		// $matches[3] = "mode=view&f=5"
		//if (!empty($matches[2])) //	Admin
		if ( isset($matches[2]) && !empty($matches[2]) ) // Admin
		{
			foreach	($mvModules as $name =>	$value)
			{
				if ($value['state'] == MODULE_ENABLED || $value['state'] == MODULE_DEFAULT)
				{
					if (in_array("$matches[1].$phpEx", $value['admin']))
					{
						$url = $root_path . "admin/index.$phpEx$first_sepmodule=$name&file=$matches[1]" . ($matches[3]	? "&$matches[3]" : '');
						break;
					}
				}
			}
		}
		else if	($mvModuleSearch != '' && in_array("$matches[1].$phpEx", $mvModules[$mvModuleSearch]['files']))
		{
			$url = 'index.' . $phpEx . $first_sep . 'module=' . $mvModuleSearch . '&amp;file=' . $matches[1] . (!empty($matches[3]) ? '&amp;' . $matches[3] : '');
		}
	}
	return $url;
}

function enabledModule($modulename)
{
	if (getModuleStatus($modulename) == MODULE_ENABLED || getModuleStatus($modulename) == MODULE_DEFAULT)
	{
		return true;
	}
	else
	{
		return false;
	}
}

function getModuleStatus($modulename)
{
	global $mvModules;

	return $mvModules[$modulename]['state'];
}

function getModuleID($modulename)
{
	global $mvModules;

	return $mvModules[$modulename]['id'];
}

function getModuleName($module_id)
{
	global $mvModules;

	$module_name = '';
	foreach ($mvModules as $name => $value)
	{
		if ($value['id'] == $module_id)
		{
			$module_name = $name;
		}
	}

	return $module_name;
}

function getModuleDisplayName($modulename)
{
	global $mvModules;

	return $mvModules[$modulename]['displayname'];
}

function getModuleDependency($modulename)
{
	if (enabledModule($modulename))
	{
		return getModuleVersion($modulename);
	}
	else
	{
		return 0;
	}
}

/***
* Temporarily force the use of a module template.
*  - Required if you need to access a template file from a hook and the template file (.tpl) belongs to a module.
*  - Temporarily changes the template related varibles so the template class can find the required template file (.tpl).
*  - NOTE! : call "exitModuleTemplate" when you are done.
***/
function enterModuleTemplate($modulename)
{
	global $mvModule_root_path, $root_path, $template;

	//$mvModuleTemplates = $mvModules[$modulename]['templates'];
	$template->set_modulerootdir($modulename);
	$mvModule_root_path = $root_path . 'modules/' . $modulename . '/';
}

/***
* Restore the module template settings
***/
function exitModuleTemplate()
{
	global $mvModuleName, $mvModule_root_path, $root_path, $template;

	$template->set_rootdir($template->old_root);

	if ($mvModuleName != '')
	{
		$mvModule_root_path = $root_path . 'modules/' . $mvModuleName . '/';
	}
	else
	{
		$mvModule_root_path = '';
	}
}

//
// Block management functions
//
function reorderBlocks($layout_id)
{
    global $db, $lang;

    $sql = "SELECT DISTINCT block_position FROM " . BLOCKS_TABLE . " WHERE layout_id = '" . $layout_id . "'";
    if( !$result = $db->sql_query($sql) )
    {
        message_die(GENERAL_ERROR, 'Could not query blocks table', $lang['Error'], __LINE__, __FILE__, $sql);
    }
    $rows = $db->sql_fetchrowset($result);

    $db->sql_freeresult($result);

	$num_rows = count($rows);
    for($i = 0; $i < $num_rows; $i++)
    {
        $sql = "SELECT block_id FROM ". BLOCKS_TABLE . " WHERE layout_id = '" . $layout_id . "' AND block_position = '" . $rows[$i]['block_position'] . "' ORDER BY block_weight ASC";
        if( !$result1 = $db->sql_query($sql) )
        {
            message_die(GENERAL_ERROR, 'Could not query blocks table', $lang['Error'], __LINE__, __FILE__, $sql);
        }
        $weight = 0;
        while( $row = $db->sql_fetchrow($result1) )
        {
            $weight++;
            $sql = "UPDATE " . BLOCKS_TABLE . " SET block_weight = '" . $weight . "' WHERE block_position = '" . $rows[$i]['block_position'] . "' AND block_id = '" . $row['block_id'] . "'";
            if( !$result2 = $db->sql_query($sql) )
            {
                message_die(GENERAL_ERROR, 'Could not update blocks table', $lang['Error'], __LINE__, __FILE__, $sql);
            }
        }
    }
}

/*
Returns the following....
	'1' = Guests only
	'2' = Registered Users
	'3' = Content Owner
	'4' = Admin
*/
// $content_user_id is an optional parameter for testing if the user is the content owner
function get_user_level($content_user_id = 0)
{
	global $userdata;

	$user_level = 0;

	if ($userdata['user_id'] ==	ANONYMOUS)
	{
		$user_level = 1; //Guest
	}

	if ( $userdata['session_logged_in'] )
	{
		$user_level = 2; //Registered
	}

	if ( ($content_user_id != 0) && ($content_user_id == $userdata['user_id']) )
	{
		$user_level = 3; // Content Owner
	}

	if ( $userdata['user_level'] == ADMIN )
	{
		$user_level = 4; //Administrator
	}

	return $user_level;
}

// $req_user_level is the required user level
// $content_user_id is an optional parameter for testing if the user is the content owner
// returns boolean ; true if the user is permitted access
function userLevelAccess($req_user_level, $content_user_id = 0)
{

	//If the $req_user_level is 0 (All Users) the user has access
	if ($req_user_level == 0)
	{
		return true;
	}

	//Get the users level
	$user_level = get_user_level($content_user_id);

	//If the $req_user_level is 1 (Guests Only) and user is a Guest then user has access
	if ($req_user_level == 1 && $user_level == 1)
	{
		return true;
	}

	//If the $auth_level is 1 (Guests Only) and user is NOT a Guest then user has NO access
	elseif ($req_user_level == 1 && $user_level != 1)
	{
		return false;
	}

	//If the users level is equal to or great than the required $auth level then user has access
	elseif ($user_level >= $req_user_level)
	{
		return true;
	}

	//We fell through, user has no access.
	else
	{
		return false;
	}
}

// $req_groups is an array of group ids. The user need to be a member of one of these groups for access to be permitted.
// returns boolean ; true if the user is permitted access
function groupLevelAccess($req_groups)
{
	global $userdata;

	//If the group_row is empty the user doesn't need group membership, no need for additional checks.
	if (empty($req_groups))
	{
		return true;
	}

	//Anonymous users can't be group members so there is no point in going any further
	if ($userdata['user_id'] == ANONYMOUS && !empty($req_groups))
	{
		return false;
	}

	$group_content = explode(',', $req_groups);

	$group_count = count($group_content);
    for	($i	= 0; $i	< $group_count; $i++)
	{
		if(in_array(intval($group_content[$i]),	obtain_users_groups($userdata['user_id'])))
		{
			return true;
		}
	}

	return false;
}

// Determine if a user has permission to access based on their user level and group membership
// $req_user_level is the required user level
// $req_groups is an array of group ids. The user need to be a member of one of these groups for access to be permitted.
// $content_user_id is an optional parameter for testing if the user is the content owner
// returns boolean ; true if the user is permitted access
function access_permitted($req_user_level, $req_groups = '', $content_user_id = 0)
{
    if (!userLevelAccess($req_user_level, $content_user_id))
	{
		return false;
	}

	if (!groupLevelAccess($req_groups))
	{
		return false;
    }

	// If we got here the user is permitted access
	return true;
}

// Prepare a comma seperated list of groups, from $_POST['groups'] for storing in the DB
function prepare_group_list()
{
	global $db;

	$sql = "SELECT MAX(group_id) max_group_id FROM " . GROUPS_TABLE . " WHERE group_single_user = 0";
	if( !($result = $db->sql_query($sql)) )
	{
		message_die(CRITICAL_ERROR, 'Could not query user groups information', '', __LINE__, __FILE__, $sql);
	}
	$row = $db->sql_fetchrow($result);

	$group_list = '';

	for ($i = 1; $i <= $row['max_group_id']; $i++)
	{
		if (isset($_POST['group' . strval($i)]))
		{
			$group_list .= ($group_list != '') ? ',' . strval($i) : strval($i);
		}
	}

	return $group_list;
}

function parseBlocks($layout_id)
{
    global $db, $template, $userdata, $root_path, $phpEx, $lang;
    global $mvModules, $block_position, $block_path;

	$block_row = array();

	$sql = 'SELECT * FROM ' . BLOCKS_TABLE . " WHERE layout_id ='" . $layout_id . "' ORDER BY block_weight";

    if( !($result = $db->sql_query($sql)) )
    {
        message_die(CRITICAL_ERROR, 'Could not query blocks information', '', __LINE__, __FILE__, $sql);
    }

    $block_row = $db->sql_fetchrowset($result);

    $db->sql_freeresult($result);

	$block_count = count($block_row);

    for ($i = 0; $i < $block_count; $i++)
    {
		foreach ($mvModules as $name => $value)
		{
			if ( ($value['state'] == MODULE_ENABLED || $value['state'] == MODULE_DEFAULT) && $value['type'] == ADDON_BLOCK )
			{
				if ($block_row[$i]['module_id'] == $value['id'])
				{
					//Can this user access this block?
					if ( access_permitted($block_row[$i]['block_view'], $block_row[$i]['groups']) )
					{
						$block_path = $root_path . 'modules/' . $value['module_name'] . '/';
						$block_file = $block_path . 'index.' . $phpEx;

						if (@file_exists(realpath($block_file)))
						{
							$template->set_modulerootdir($value['module_name']);

							// Set the block position label for the template switches.
							switch ($block_row[$i]['block_position'])
							{
								case BLOCK_TOP:
									$block_position = 'top';
									$template->assign_var('S_TOP_BLOCKS', true);
									break;
								case BLOCK_LEFT:
									$block_position = 'left';
									$template->assign_var('S_LEFT_BLOCKS', true);
									break;
								case BLOCK_RIGHT:
									$block_position = 'right';
									$template->assign_var('S_RIGHT_BLOCKS', true);
									break;
								case BLOCK_BOTTOM:
									$block_position = 'bottom';
									$template->assign_var('S_BOTTOM_BLOCKS', true);
									break;
							}

							include($block_file);

							$template->set_rootdir($template->old_root);
						}
						else
						{
							// TODO - notify that the block was not found is some way?
						}
					}
				}
			}
		}
	}
	//Unset these global vars which we don't need outside of the block parser
	unset($block_path);
	unset($block_position);
}

//
// Generic function to display an error message if a block hit a problem.
//
function block_error($title, $error)
{
	global $lang, $template, $block_position;

	//Block error is called when the template context is already that of the block.
	//We need to get back to the core template :-)
	$template->set_rootdir($template->old_root);

	$template->set_filenames(array(
		'block_error_body' => 'block_error_body.tpl'
		)
	);

	$template->assign_vars(array(
		'TITLE' 	  => $title,
		'BLOCK_ERROR' => $error,
		)
	);

	$template->assign_block_vars($block_position, array());
	$template->assign_block_var_from_handle($block_position . '.OUTPUT', 'block_error_body');
}

//
// Layout management functions
//

// returns an array of the layout requested or the default layout if the requested layout couldn't be found
function getLayout($layout)
{
	global $db, $userdata, $config;

	//Get the named layout ($layout) and the default layout
	$sql = 'SELECT *
		FROM ' . LAYOUT_TABLE . '
		WHERE layout_url = "' . $layout . '" OR layout_id= "' . $config['default_layout'] . '"';

	if(	!($layout_result = $db->sql_query($sql)) )
	{
		message_die(CRITICAL_ERROR,	'Could not query layout information', '', __LINE__, __FILE__, $sql);
	}

	$layout_rows = $db->sql_fetchrowset($layout_result);
	$db->sql_freeresult($layout_result);

    //Store the selected layout and the default layout in an array
	$default_row = array();
	$layout_row = array();

	$layout_count = count($layout_rows);

    for	($i	= 0; $i	< $layout_count; $i++)
	{
		if ($layout_rows[$i]['layout_id'] == $config['default_layout'])
		{
			$default_row = $layout_rows[$i];
		}

		if ($layout_rows[$i]['layout_url'] == $layout)
		{
			$layout_row = $layout_rows[$i];
		}
	}

	//If we didn't find the requested layout return the default layout instead
    if (!empty($layout_row))
    {
    	return $layout_row;
    }
    else
    {
    	return $default_row;
    }
}

function initModules()
{
	global $db, $lang, $root_path, $phpEx, $config, $table_prefix, $template;
	global $mvDefaultModuleName, $mvValidModuleName, $mvReqModuleName, $mvModuleName, $mvModule_root_path;
	global $mvModules, /*$mvPages, $mvLayouts,*/ $mvModuleTemplates;

	//Get the module data
	$sql = 'SELECT * FROM ' . MODULES_TABLE;
	if (!($result = $db->sql_query($sql)))
	{
		message_die(CRITICAL_ERROR, 'Could not query module information', '', __LINE__, __FILE__, $sql);
	}

	while ($row = $db->sql_fetchrow($result))
	{
		$name = $row['module_name'];

		$mvModules[$name]['module_name'] = $name;
		$mvModules[$name]['id'] = $row['module_id'];
		$mvModules[$name]['type'] = $row['module_type'];
		$mvModules[$name]['displayname'] = $row['module_displayname'];
		$mvModules[$name]['description'] = $row['module_description'];
		$mvModules[$name]['version'] = $row['module_version'];
		$mvModules[$name]['version_check'] = $row['module_version_check'];
		$mvModules[$name]['copyright'] = $row['module_copyright'];
		$mvModules[$name]['files'] = explode(', ', $row['module_files']);
		$mvModules[$name]['templates'] = explode(', ', $row['module_templates']);
		$mvModules[$name]['admin'] = explode(', ', $row['module_admin']);
		$mvModules[$name]['language'] = explode(', ', $row['module_language']);
		$mvModules[$name]['components'] = explode(', ', $row['module_components']);
		$mvModules[$name]['constants'] = explode(', ', $row['module_constants']);
		$mvModules[$name]['headers'] = explode(', ', $row['module_headers']);
		$mvModules[$name]['state'] = $row['module_state'];
	}
	$db->sql_freeresult($result);

	$mvDefaultModuleName = '';
	$mvValidModuleName = '';

	//Check the version info and get the constants
	foreach ($mvModules as $name => $value)
	{
		//Compare the installed module version against the details in mvVersion.php
		$mvVersion = array();
		@include($root_path . 'modules/' . $name . '/mvVersion.' . $phpEx);

		//print $name . ' ' . $value['state'] . ' ' . $value['version'] . ' ' . $mvVersion['version'] . "\n";

	 	//Versions differ, set this module to "upgrade required" status to prevent its use.
		if (trim($value['version']) != trim($mvVersion['version']))
		{
			$value['state'] = MODULE_UPDATE_REQUIRED;
			$mvModules[$name]['state'] = MODULE_UPDATE_REQUIRED;
		}
		unset($mvVersion);

		//If the module is enabled or default, check the requested vars and get the constants.
		if ($value['state'] == MODULE_ENABLED || $value['state'] == MODULE_DEFAULT)
		{
			$mvModuleName = $name;
			$mvModule_root_path = $root_path . 'modules/' . $mvModuleName . '/';

			if ($mvReqModuleName != '')
			{
				if (strtolower($name) == $mvReqModuleName)
				{
					$mvValidModuleName = $name;
				}
			}

			if ($value['state'] == MODULE_DEFAULT)
			{
				$mvDefaultModuleName = $name;
			}

			// include the mvConstants.php file
			foreach ($value['constants'] as $file)
			{
				@include($root_path . 'modules/' . $name . '/' . $file);
			}
		}
	}

	$mvModuleName = '';
	$mvModule_root_path = '';
}

?>